package com.sykj.why.mongo.dao.impl;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.mongodb.DBObject;
import com.mongodb.WriteResult;
import com.sykj.why.exception.WhyException;
import com.sykj.why.mongo.dao.BaseDao;
import com.sykj.why.mongo.document.ServiceDocument;
import com.sykj.why.mongo.dto.PageDTO;
import com.sykj.why.mongo.enums.exception.ResultEnum;
import com.sykj.why.util.BaseTools;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: why
 * @description:
 * @author: hqz
 * @create: 2018-09-06 12:41
 **/
@Repository("baseDao")
public class BaseDaoImpl<T extends ServiceDocument> implements BaseDao<T> {
    public final static String PROVINCEID = "provinceId";
    public final static String CITYID = "cityId";
    public final static String AREAID = "areaId";
    public final static String VILLAGEID = "villageId";


    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    public void save(T entity) {
        entity.setCreateTime(BaseTools.systemtimeLong());
        entity.setUpdateTime(BaseTools.systemtimeLong());
        entity.setEnable(true);
        mongoTemplate.save(entity);
    }

    @Override
    public void save(HttpServletRequest request, T entity) {
        if (request.getSession().getAttribute(PROVINCEID) != null) {
            entity.setProvinceId(request.getSession().getAttribute(PROVINCEID).toString());
        }
        if (request.getSession().getAttribute(CITYID) != null) {
            entity.setCityId(request.getSession().getAttribute(CITYID).toString());
        }
        if (request.getSession().getAttribute(AREAID) != null) {
            entity.setAreaId(request.getSession().getAttribute(AREAID).toString());
        }
        if (request.getSession().getAttribute(VILLAGEID) != null) {
            entity.setVillageId(request.getSession().getAttribute(VILLAGEID).toString());
        }
        entity.setCreateTime(BaseTools.systemtimeLong());
        entity.setUpdateTime(BaseTools.systemtimeLong());
        mongoTemplate.save(entity);
    }

    @Override
    public void save(List<T> list) {
        List<T> tList = new ArrayList<>();
        for (T t : list) {
            t.setCreateTime(BaseTools.systemtimeLong());
            t.setUpdateTime(BaseTools.systemtimeLong());
            tList.add(t);
        }
        mongoTemplate.insertAll(tList);
    }

    @Override
    public void saveOrupdate(T entity) {
        entity.setUpdateTime(BaseTools.systemtimeLong());
        mongoTemplate.save(entity);
    }

    @Override
    public void remove(T entity) {
        if (!entity.getRemoved()) {
            entity.setRemoved(true);
            entity.setUpdateTime(BaseTools.systemtimeLong());
            mongoTemplate.save(entity);
        }
    }

    @Override
    public void disableOrEnable(T entity, boolean flag) {
        entity.setEnable(flag);
        entity.setUpdateTime(BaseTools.systemtimeLong());
        mongoTemplate.save(entity);
    }

    @Override
    public void setTop(T entity, boolean top) {
        if (top) {
//            entity.setIsTop(BaseTools.systemtimeLong());
        } else {
//            entity.setIsTop(0);
        }
        entity.setUpdateTime(BaseTools.systemtimeLong());
        mongoTemplate.save(entity);
    }

    /**
     * 设置推送状态
     * @param entity
     * @param flag true为推送 false 为取消推送
     */
    @Override
    public void setPush(T entity, boolean flag) {
        entity.setPushStatus(flag);
        entity.setUpdateTime(BaseTools.systemtimeLong());
        mongoTemplate.save(entity);
    }


    @Override
    public void sort(T entity, int sort) {
        entity.setSort(sort);
        entity.setUpdateTime(BaseTools.systemtimeLong());
        mongoTemplate.save(entity);
    }


    @Override
    public void delete(ServiceDocument entity) {
        mongoTemplate.remove(entity);
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public List<T> findAll(Class cls) {
        return mongoTemplate.findAll(cls);
    }

    @Override
    public List<T> findAll(String name, String val, Class<T> t, boolean removed) {
        Query query = new Query();
        query.addCriteria(Criteria.where(name).is(val).and("removed").is(removed));
        return mongoTemplate.find(query, t);
    }

    @Override
    public List<T> findAll(Query query, Class<T> t) {
        return mongoTemplate.find(query, t);
    }

    /**
     * 根据条件查询总记录数
     */
    @Override
    public long count(Query query, Class<T> t) {
        // TODO Auto-generated method stub
        List<T> list = mongoTemplate.find(query, t);
        return list.size();
    }

    @Override
    public List<T> findAll(Class<T> t, boolean removed) {
        return mongoTemplate.find(new Query(Criteria.where("removed").is(removed)), t);
    }

    @Override
    public int getPageSize(long totalCount, int lineSize) {
        int pageSize;
        if (totalCount % lineSize == 0) {
            pageSize = (int) totalCount / lineSize;
        } else {
            pageSize = (int) totalCount / lineSize + 1;
        }
        return pageSize;
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public T get(Class cls, String id, boolean removed) {
        if (StringUtils.isBlank(id)) {
            throw new WhyException(ResultEnum.IDISNULL);
        }
        return (T) mongoTemplate.findOne(new Query(Criteria.where("id").is(id).and("removed").is(removed)), cls);
    }

    @Override
    public T get(Class cls, String id) {
        if (StringUtils.isBlank(id)) {
            throw new WhyException(ResultEnum.IDISNULL);
        }
        return (T) mongoTemplate.findOne(new Query(Criteria.where("id").is(id)), cls);
    }


    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public T get(String fieldName, Object getValue, Class cls, boolean removed) {
        if (getValue == null) {
            throw new WhyException(fieldName, ResultEnum.PARAMISNULL);
        }
        return (T) mongoTemplate.findOne(new Query(Criteria.where(fieldName).is(getValue).and("removed").is(removed)), cls);
    }


    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public T get(String fieldNameOne, Object getValueOne, String fieldNameTwo, Object getValueTwo, Class cls, boolean removed) {
        return (T) mongoTemplate.findOne(new Query(Criteria.where(fieldNameOne).is(getValueOne).and(fieldNameTwo).is(getValueTwo).and("removed").is(removed)), cls);
    }


    @Override
    public T findOne(Query query, Class<T> t) {
        return (T) mongoTemplate.findOne(query, t);
    }

    @SuppressWarnings("rawtypes")
    @Override
    public boolean update(String fieldName, Object updatevalue, String id, Class entity) {
        WriteResult writeResult = null;
        boolean result = false;
        writeResult = mongoTemplate.updateFirst(new Query(Criteria.where("id").is(id)), new Update().set(fieldName, updatevalue), entity);
        if (writeResult != null) {
            if (writeResult.getN() > 0) {
                result = true;
            } else {
                result = false;
            }
        } else {
            result = false;
        }
        return result;
    }

    @SuppressWarnings("rawtypes")
    @Override
    public boolean updateAll(String fieldName, Object updatevalue, String updateId, String id, Class entity) {
        WriteResult writeResult = null;
        boolean result = false;
        writeResult = mongoTemplate.updateMulti(new Query(Criteria.where(updateId).is(id)), new Update().set(fieldName, updatevalue), entity);
        if (writeResult != null) {
            if (writeResult.getN() > 0) {
                result = true;
            } else {
                result = false;
            }
        } else {
            result = false;
        }
        return result;
    }

    @Override
    public long count(Class<T> c, boolean removed) {
        Query query = new Query();
        query.addCriteria(Criteria.where("removed").is(false));

        return mongoTemplate.count(query, c);
    }

    @SuppressWarnings("rawtypes")
    @Override
    public long count(String fieldName, Object selRemoved, Class entity) {
        return mongoTemplate.count(new Query(Criteria.where(fieldName).is(selRemoved)), entity);
    }

    @SuppressWarnings("rawtypes")
    @Override
    public long count(String fieldName, Object selRemoved, boolean removed, Class entity) {
        return mongoTemplate.count(new Query(Criteria.where(fieldName).is(selRemoved).and("removed").is(removed)), entity);
    }

    @SuppressWarnings("rawtypes")
    @Override
    public long count(String fieldName1, Object selRemoved1, String fieldName2, Object selRemoved2, boolean removed, Class entity) {
        return mongoTemplate.count(new Query(Criteria.where(fieldName1).is(selRemoved1).and(fieldName2).is(selRemoved2).and("removed").is(removed)), entity);
    }

    @Override
    public List<T> findByPage(Query query, int currentPage, int lineSize, Class<T> t) {
        query.skip((currentPage - 1) * lineSize);
        query.limit(lineSize);
        return mongoTemplate.find(query, t);
    }

    @Override
    public List<T> findByPage(Query query, PageDTO page, Class<T> t) {
        query.skip((page.getCurrentPage() - 1) * page.getLineSize());
        query.limit(page.getLineSize());
        return mongoTemplate.find(query, t);
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<T> findDistinctAll(String collection, String key) {
        // TODO Auto-generated method stub
        return mongoTemplate.getCollection(collection).distinct(key);
    }

    @Override
    public List<T> findDistinctAll(String collectionName, String key, DBObject query) {
        return mongoTemplate.getCollection(collectionName).distinct(key, query);
    }

    @Override
    public AggregationResults<T> aggregate(Aggregation aggregation, String collectionName, Class<T> entity) {
        return mongoTemplate.aggregate(aggregation, collectionName, entity);
    }
}
